package org.fuys.coder.domain.audit.service.impl;

import org.fuys.coder.domain.audit.model.event.AsyncAuditEvent;
import org.fuys.coder.domain.audit.model.event.AsyncTaskIdHolder;
import org.fuys.coder.domain.audit.model.event.AsyncTasksOverEvent;
import org.fuys.coder.domain.audit.model.req.AuditTask;
import org.fuys.coder.domain.audit.model.res.AuditResult;
import org.fuys.coder.domain.audit.model.vo.AuditResultTypeVO;
import org.fuys.coder.domain.audit.model.vo.AuditTaskTypeVO;
import org.fuys.coder.domain.audit.service.Audit;
import org.fuys.coder.domain.audit.service.policy.audit.AuditStrategy;
import org.fuys.coder.domain.audit.service.policy.result.AuditResultStrategy;
import org.fuys.coder.domain.audit.service.publisher.AsyncAuditEventPublisher;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.util.Map;

/**
 * @projectName: fuys-low-coder
 * @package: org.fuys.coder.domain.audit.service.impl
 * @className: DynamicAuditServiceImpl
 * @author: WangJing
 * @description: 动态组合审核策略进行审核
 * @date: 2024/6/22 17:07
 * @version: 1.0
 */
@Service("dynamicAuditServiceImpl")
public class DynamicAuditServiceImpl implements Audit {

    private final Map<String, AuditStrategy> strategyMap;
    private final Map<String, AuditResultStrategy> resultStrategyMap;
    @Resource
    private AsyncAuditEventPublisher publisher;


    @Autowired
    public DynamicAuditServiceImpl(ListableBeanFactory beanFactory){
        //todo 仍有错误没有解决 该怎么准确的确定采用的策略呢？
        //todo 今天状态不好 明天处理审核任务的接口 要传递给每个种类的策略AuditTask用于上下文的操作进行
        final Map<String, AuditStrategy> beansOfType = beanFactory.getBeansOfType(AuditStrategy.class);
        resultStrategyMap = beanFactory.getBeansOfType(AuditResultStrategy.class);
        strategyMap=beansOfType;
    }

    @Override
    public AuditResult doAudit(AuditTask auditTask) {
        //这里只负责指挥和调配 也就是说 线程池进行审核的处理需要在具体的逻辑中进行
        String strategy = getTaskStrategy(auditTask);
        if(strategyMap.containsKey(strategy)){
            final AuditStrategy auditStrategy = strategyMap.get(strategy);
            final AuditResult execute = auditStrategy.execute(auditTask);
            if(!ObjectUtils.isEmpty(execute)&&execute.isFinish()&&auditTask.isNeedResultHandle()) {
                //返回审核的结果 并且在这里进行处理审核结果(如果此任务需要的话)
                this.resultHandle(execute,auditTask);
            }else{
                if(ObjectUtils.isEmpty(execute)&&auditTask.getType()!=AuditTaskTypeVO.MULTIPLE.getIndex()){
                    //todo 否则则是因为种种原因审核失败 交给人工复审
                    final AuditResultStrategy review = this.resultStrategyMap.get(AuditResultTypeVO.REVIEW.getStrategy());
                    review.handleResult(execute,auditTask);
                }
                //如果结果非空 说明一定是此审核任务没有完成 也就说是一个异步审核请求 有可能是和内容审核相关 有可能只是一个大图片审核
            }
            return execute;
        }
        return null;
    }

    private void resultHandle(AuditResult execute,AuditTask task) {
        //确定审核任务结束了
        if(execute.isFinish()&&task.isNeedResultHandle()) {
            final String resultStrategy = this.getResultStrategy(execute);
            if (resultStrategyMap.containsKey(resultStrategy)) {
                final AuditResultStrategy auditResultStrategy = resultStrategyMap.get(resultStrategy);
                auditResultStrategy.handleResult(execute,task);
            } else {
                //todo 审核结束之后的逻辑
            }
        }
    }

    private String getTaskStrategy(AuditTask auditTask){
        return AuditTaskTypeVO.getByIdx(auditTask.getType()).getStrategy();
    }

    private String getResultStrategy(AuditResult auditResult){
        return AuditResultTypeVO.getByIdx(auditResult.getType()).getStrategy();
    }

    @Component
    public class AsyncAuditEventListener implements ApplicationListener<AsyncAuditEvent>{

        @Override
        public void onApplicationEvent(AsyncAuditEvent event) {
            final AuditResult auditResult = event.getAuditResult();
            final String taskId = auditResult.getTaskId();
            if(!ObjectUtils.isEmpty(taskId)){
                //如果任务id非空 说明它是一个任务的子任务 将其归位
                final Integer taskNowNums = AsyncTaskIdHolder.incrementTaskNowNums(taskId);
                if(taskNowNums.equals(AsyncTaskIdHolder.getTaskAllNums(taskId))){
                    AsyncTasksOverEvent overEvent=new AsyncTasksOverEvent(this);
                    overEvent.setTaskId(taskId);
                    publisher.publishTaskOverEvent(overEvent);
                    return;
                }
                return;
            }
            resultHandle(auditResult,event.getAuditTask());
        }

    }

}
